#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <stdbool.h>
#include <avr/eeprom.h>

extern void Init(void);
void spi_work();
void key_do(uint8_t Num, bool press);
void spi_transmit(uint16_t data);
void key_work(void);
void fs_work(void);
void Clean_On();
void Crunch_On();
void fs_do(uint8_t fs_num, uint8_t press);
void Lead1_On();
void Lead2_On();
void key_check();
void Start_Delay(uint16_t Val, uint8_t Spi);
void key_alarm();

#define StartChange 150
//#define GoChange    20
//#define EndChange   1
#define KeyDelay    30
#define FsDelay     120

#define SETBIT(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define CLEARBIT(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
#define CHECKBIT(ADDRESS,BIT) (ADDRESS & (1<<BIT))

#define Key_Clean  (CHECKBIT(PIND,PIND6))
#define Key_Crunch (CHECKBIT(PIND,PIND5))
#define Key_Lead1  (CHECKBIT(PIND,PIND7))
#define Key_Lead2  (CHECKBIT(PIND,PIND4))
#define Key_Loop   (CHECKBIT(PIND,PIND2))
#define Key_Master (CHECKBIT(PIND,PIND3))
#define Fsw1En     (CHECKBIT(PINC,PINC2))
#define Fsw1Tip    (CHECKBIT(PINC,PINC0))
#define Fsw1Ring   (CHECKBIT(PINC,PINC1))
#define Fsw2En     (CHECKBIT(PINC,PINC5))
#define Fsw2Tip    (CHECKBIT(PINC,PINC3))
#define Fsw2Ring   (CHECKBIT(PINC,PINC4))
#define Fsw3En     (CHECKBIT(PINB,PINB0))
#define Fsw3Tip    (CHECKBIT(PIND,PIND0))
#define Fsw3Ring   (CHECKBIT(PIND,PIND1))

enum {Key_Clean_En, Key_Crunch_En, Key_Lead1_En, Key_Lead2_En, Key_Loop_En, Key_Master_En};
enum {Fs1_Tip_En,   Fs1_Ring_En,   Fs2_Tip_En,   Fs2_Ring_En};

#define MuteOff     SETBIT(PORTB,PB2)
#define MuteOn     CLEARBIT(PORTB,PB2)
#define SpiStrob   SETBIT(PORTB,PB1);CLEARBIT(PORTB,PB1)

uint16_t adr = 0;

uint8_t Key_Clean_Tmp;
uint8_t Key_Crunch_Tmp;
uint8_t Key_Lead1_Tmp;
uint8_t Key_Lead2_Tmp;
uint8_t Key_Loop_Tmp;
uint8_t Key_Master_Tmp;
uint8_t Fsw3En_Tmp;

uint8_t Key_Flash;

uint8_t Key_Clean_Alarm;
uint8_t Key_Crunch_Alarm;
uint8_t Key_Lead1_Alarm;
uint8_t Key_Lead2_Alarm;
uint8_t Key_Loop_Alarm;
uint8_t Key_Master_Alarm;

static volatile uint8_t Timer;
static volatile uint8_t Fsw1TipTmp;
static volatile uint8_t Fsw1RingTmp;

static volatile uint8_t Fsw2TipTmp;
static volatile uint8_t Fsw2RingTmp;

static volatile uint8_t Fsw3TipTmp;
static volatile uint8_t Fsw3RingTmp;

uint16_t DelaySwitch;

//uint8_t DelaySwitch1Tip;
uint16_t DelayFootSwitch;
//uint8_t DelaySwitch2Tip;
//uint8_t DelaySwitch2Ring;

uint8_t adc_start;
uint8_t adc_data;
bool 	Power_Error;

#define MASK 0b1111111000000000

typedef union
{
    struct
    {
        uint8_t PlR_Power      : 1;
        uint8_t P6_Vol1_Vol2   : 1;
        uint8_t Tmp_CL_CR      : 1;
        uint8_t P4_CL_CR       : 1;
        uint8_t Tmp_L1_L2      : 1;
        uint8_t nc0            : 1;
        uint8_t P5_CC_LL       : 1;
        uint8_t P123_L1_L2     : 1;

        uint8_t nc1            : 1;
        uint8_t Led_B          : 1;
        uint8_t Led_A          : 1;
        uint8_t Led_CRUNCH     : 1;
        uint8_t Led_CLEAN      : 1;
        uint8_t Led_LEAD2      : 1;
        uint8_t Led_LOOP       : 1;
        uint8_t Led_LEAD1      : 1;
    }
    pw0; uint16_t PW0;
} u_pw0;
u_pw0 U_PW0;


ISR(INT0_vect){};
ISR(PCINT0_vect){};
ISR(PCINT1_vect){};
ISR(PCINT2_vect){};
ISR(WDT_vect){};
ISR(TIMER2_COMPA_vect){};
ISR(TIMER2_COMPB_vect){};
ISR(TIMER2_OVF_vect){};
ISR(TIMER1_CAPT_vect){};
ISR(TIMER1_COMPA_vect){};
ISR(TIMER1_COMPB_vect){};
ISR(TIMER1_OVF_vect){};
ISR(TIMER0_COMPA_vect){};
ISR(TIMER0_COMPB_vect){};
ISR(SPI_STC_vect){};
ISR(USART_RX_vect){};
ISR(USART_UDRE_vect){};
ISR(USART_TX_vect){};
ISR(ADC_vect)
{
    Timer = true;
}
ISR(EE_READY_vect){};
ISR(ANALOG_COMP_vect){};
ISR(TWI_vect){};
ISR(SPM_READY_vect){};
ISR(TIMER0_OVF_vect)
{
    TCNT0 = 0;
    Timer = true;
}

int main(void)
{
    Init();
    MuteOn;
    key_check();
    Key_Flash =	DelaySwitch = 0;
	Power_Error = false;
	adc_start = 25;

    sei();

    ADCSRA |= 0b01000000;

//    U_PW0.PW0 = 0;
//    Start_Delay(U_PW0.PW0, true);
//    Start_Delay(U_PW0.PW0, false);
//    Start_Delay(U_PW0.PW0, false);


    U_PW0.PW0 = eeprom_read_word((uint16_t*)adr);
	if(U_PW0.PW0==0xffff)
		U_PW0.PW0 = 0x1530;

	if(!Fsw3En)
		{
    	key_do(Key_Master_En, Fsw3TipTmp);
    	key_do(Key_Loop_En, Fsw3RingTmp);
		DelaySwitch = 0;
		}

    Start_Delay(U_PW0.PW0|0b0001000000000000, true);

    Start_Delay(U_PW0.PW0|0b0000100000000000, true);

    Start_Delay(U_PW0.PW0|0b1000000000000000, true);

    Start_Delay(U_PW0.PW0|0b0010000000000000, true);

    Start_Delay(U_PW0.PW0|0b0000010000000000, true);

    Start_Delay(U_PW0.PW0|0b0000001000000000, true);

    Start_Delay(U_PW0.PW0|0b0100000000000000, true);

    Start_Delay(U_PW0.PW0, true);

//    U_PW0.PW0 = eeprom_read_word((uint16_t*)adr);
//	if(U_PW0.PW0==0xffff)
//		U_PW0.PW0 = 0x1530;
//    DelaySwitch = StartChange;


    while (1)
    {
        wdt_reset();
        if(Timer)
        {
            Timer = false;
            spi_work();
            key_work();
            fs_work();
            key_alarm();
        }
    }
}

void spi_transmit(uint16_t data)
{
    data ^= MASK;
    SPDR = (data>>8);
    while (!(SPSR&(1<<SPIF))){};
    SPDR = (data&0xff);
    while (!(SPSR&(1<<SPIF))){};
    SpiStrob;
}

void spi_work()
{
    if(DelaySwitch>StartChange-17)
    {
        MuteOn;
        if(DelaySwitch==(StartChange-14))
        {
            if(Power_Error)
                spi_transmit(0x0000);
            else
            {
                spi_transmit(U_PW0.PW0);
                eeprom_write_word ((uint16_t*) adr, U_PW0.PW0);
            }
        }
    }
    else
    {
        if(!Power_Error)
            MuteOff;
    }
    if(DelaySwitch)
        DelaySwitch--;
}

void key_work() //Опрос кнопок
{
	
    if(!Key_Clean)
    {
        //		Key_Crunch_Tmp = Key_Lead1_Tmp = Key_Lead2_Tmp = Key_Loop_Tmp = Key_Master_Tmp = 0;
        if((Key_Clean_Tmp==0))
            key_do(Key_Clean_En, true);
        Key_Clean_Tmp = KeyDelay;
    }
    else
    {
        if(Key_Clean_Tmp)
            Key_Clean_Tmp--;
        else
			{
			if(Key_Clean_Alarm)
				DelaySwitch = StartChange;
            Key_Clean_Alarm=0;
			}
    }

    if(!Key_Crunch)
    {
        //		Key_Clean_Tmp = Key_Lead1_Tmp = Key_Lead2_Tmp = Key_Loop_Tmp = Key_Master_Tmp = 0;
        if((Key_Crunch_Tmp==0))
            key_do(Key_Crunch_En, true);
        Key_Crunch_Tmp = KeyDelay;
    }
    else
    {
        if(Key_Crunch_Tmp)
            Key_Crunch_Tmp--;
        else
			{
			if(Key_Crunch_Alarm)
				DelaySwitch = StartChange;
            Key_Crunch_Alarm=0;
			}
    }

    if(!Key_Lead1)
    {
        //		Key_Clean_Tmp = Key_Crunch_Tmp = Key_Lead2_Tmp = Key_Loop_Tmp = Key_Master_Tmp = 0;
        if((Key_Lead1_Tmp==0))
            key_do(Key_Lead1_En, true);
        Key_Lead1_Tmp = KeyDelay;
    }
    else
    {
        if(Key_Lead1_Tmp)
            Key_Lead1_Tmp--;
        else
			{
			if(Key_Lead1_Alarm)
				DelaySwitch = StartChange;				
            Key_Lead1_Alarm=0;
			}
    }

    if(!Key_Lead2)
    {
        //		Key_Clean_Tmp = Key_Crunch_Tmp = Key_Lead1_Tmp = Key_Loop_Tmp = Key_Master_Tmp = 0;
        if((Key_Lead2_Tmp==0))
            key_do(Key_Lead2_En, true);
        Key_Lead2_Tmp = KeyDelay;
    }
    else
    {
        if(Key_Lead2_Tmp)
            Key_Lead2_Tmp--;
        else
			{
			if(Key_Lead2_Alarm)
				DelaySwitch = StartChange;								
            Key_Lead2_Alarm=0;
			}
    }

    if(!Key_Loop)
    {
        //		Key_Clean_Tmp = Key_Crunch_Tmp = Key_Lead1_Tmp = Key_Lead2_Tmp = Key_Master_Tmp = 0;
        if((Key_Loop_Tmp==0)&&(Fsw3En))
            key_do(Key_Loop_En, U_PW0.pw0.Led_LOOP);
        Key_Loop_Tmp = KeyDelay;
    }
    else
    {
        if(Key_Loop_Tmp)
            Key_Loop_Tmp--;
        else
			{
			if(Key_Loop_Alarm)
				DelaySwitch = StartChange;								
            Key_Loop_Alarm=0;
			}
    }

    if(!Key_Master)
    {
        //		Key_Clean_Tmp = Key_Crunch_Tmp = Key_Lead1_Tmp = Key_Lead2_Tmp = Key_Loop_Tmp = 0;
        if((Key_Master_Tmp==0)&&(Fsw3En))
            key_do(Key_Master_En, U_PW0.pw0.P6_Vol1_Vol2);
        Key_Master_Tmp = KeyDelay;
    }
    else
    {
        if(Key_Master_Tmp)
            Key_Master_Tmp--;
        else
			{
			if(Key_Master_Alarm)
				DelaySwitch = StartChange;								
            Key_Master_Alarm=0;
			}
    }
	
}

void key_do(uint8_t Num, bool press)  //При нажатии/отжатии
{
    switch (Num)
    {
    case (Key_Clean_En):
        Clean_On();
        break;
    case (Key_Crunch_En):
        Crunch_On();
        break;
    case Key_Lead1_En:
        Lead1_On();
        break;
    case Key_Lead2_En:
        Lead2_On();
        break;
    case Key_Loop_En:
        Fsw3TipTmp = U_PW0.pw0.Led_LOOP = U_PW0.pw0.PlR_Power = press?false:true;
	    DelaySwitch = StartChange;
        break;
    case Key_Master_En:
        U_PW0.pw0.Led_A = press?true:false;
//		Fsw3RingTmp = press;
        U_PW0.pw0.Led_B = U_PW0.pw0.P6_Vol1_Vol2  = (!U_PW0.pw0.Led_A);
		DelaySwitch = StartChange;
        break;
    }

}

void key_check() //проверка при старте
{
    Fsw1TipTmp  = Fsw1Tip;
    Fsw1RingTmp = Fsw1Ring;
    Fsw2TipTmp  = Fsw2Tip;
    Fsw2RingTmp = Fsw2Ring;
    Fsw3TipTmp  = Fsw3Tip;
    Fsw3RingTmp = Fsw3Ring;
	Fsw3En_Tmp  = Fsw3En;

    Key_Master_Tmp = Key_Loop_Tmp = Key_Lead2_Tmp = Key_Lead1_Tmp = Key_Crunch_Tmp = Key_Clean_Tmp = KeyDelay;
//	Key_Clean_Alarm = Key_Crunch_Alarm = Key_Lead1_Alarm = Key_Lead2_Alarm = Key_Loop_Alarm = Key_Master_Alarm = false;

    if(!Key_Clean)
		Key_Clean_Alarm = true;
    if(!Key_Crunch)
		Key_Crunch_Alarm = true;
    if(!Key_Lead1)
		Key_Lead1_Alarm = true;
    if(!Key_Lead2)
		Key_Lead2_Alarm = true;
    if(!Key_Loop)
		Key_Loop_Alarm = true;
    if(!Key_Master)
		Key_Master_Alarm = true;
}

void fs_work(void)
{
	bool bTmp;

    if(Fsw1TipTmp!=Fsw1Tip)
    {
        Fsw1TipTmp=Fsw1Tip;
        if(DelayFootSwitch==0)
        {
            fs_do(Fs1_Tip_En, 2);
			if(Fsw1TipTmp==0)
            	DelayFootSwitch = FsDelay;
        }
    }

    if(Fsw1RingTmp!=Fsw1Ring)
    {
        Fsw1RingTmp=Fsw1Ring;
        if(DelayFootSwitch==0)
        {
            fs_do(Fs1_Ring_En, 2);
			if(Fsw1RingTmp==0)
            	DelayFootSwitch = FsDelay;
        }
    }

    if(Fsw2TipTmp!=Fsw2Tip)
    {
        Fsw2TipTmp=Fsw2Tip;
        if(DelayFootSwitch==0)
        {
            fs_do(Fs2_Tip_En, 2);
			if(Fsw2TipTmp==0)
            	DelayFootSwitch = FsDelay;
        }
    }

    if(Fsw2RingTmp!=Fsw2Ring)
    {
        Fsw2RingTmp=Fsw2Ring;
        if(DelayFootSwitch==0)
        {
            fs_do(Fs2_Ring_En, 2);
			if(Fsw2RingTmp==0)
            	DelayFootSwitch = FsDelay;
        }
    }

    if(!Fsw3En)  //подключен  FS 3
	{
		bTmp = Fsw3Tip?true:false;
	    if(bTmp == U_PW0.pw0.P6_Vol1_Vol2)
        	key_do(Key_Master_En, U_PW0.pw0.P6_Vol1_Vol2);

		bTmp = Fsw3Ring?true:false;
		if(bTmp == U_PW0.pw0.Led_LOOP)
			key_do(Key_Loop_En, U_PW0.pw0.Led_LOOP);
	}

	if(DelayFootSwitch)
		DelayFootSwitch--;
}

void fs_do(uint8_t fs_num, uint8_t press)  // 0-off 1-on 2-change
{
    if((!Fsw1En)&&(Fsw2En))  //подключен только FS 1
    {
        switch(fs_num)
        {
        case Fs1_Tip_En:
            if(U_PW0.pw0.Led_LEAD1 || U_PW0.pw0.Led_LEAD2)
            {
                if(!U_PW0.pw0.Tmp_CL_CR)
                    Clean_On();
                else
                    Crunch_On();
            }
            else
            {
                switch(press)
                {
                case 0:
                    Clean_On();
                    break;
                case 1:
                    Crunch_On();
                    break;
                case 2:
                    if(U_PW0.pw0.P4_CL_CR)
                        Clean_On();
                    else
                        Crunch_On();
                    break;
                }
            }
            break;

        case Fs1_Ring_En:
            if(U_PW0.pw0.Led_CLEAN || U_PW0.pw0.Led_CRUNCH)
            {
                if(!U_PW0.pw0.Tmp_L1_L2)
                    Lead1_On();
                else
                    Lead2_On();
            }
            else
            {
                switch(press)
                {
                case 0:
                    Lead1_On();
                    break;
                case 1:
                    Lead2_On();
                    break;
                case 2:
                    if(U_PW0.pw0.Led_LEAD1 )
                        Lead2_On();
                    else
                        Lead1_On();
                    break;
                }
            }
            break;
        }
    }

    if((Fsw1En)&&(!Fsw2En)) //подключен только FS 2
    {
        if(fs_num==Fs2_Ring_En)
        {
            if(U_PW0.pw0.Led_CLEAN)
                Crunch_On();
            else
            {
                if(U_PW0.pw0.Led_CRUNCH)
                    Lead1_On();
                else
                {
                    if(U_PW0.pw0.Led_LEAD1)
                        Lead2_On();
                    else
                        Clean_On();
                }
            }
        }

        if(fs_num==Fs2_Tip_En)
        {
            if(U_PW0.pw0.Led_LEAD2)
                Lead1_On();
            else
            {
                if(U_PW0.pw0.Led_LEAD1)
                    Crunch_On();
                else
                {
                    if(U_PW0.pw0.Led_CRUNCH)
                        Clean_On();
                    else
                        Lead2_On();
                }
            }
        }
    }

    if((!Fsw1En)&&(!Fsw2En)) //подключен FS1 И FS2
    {
        if(fs_num==Fs1_Tip_En)
            Clean_On();
        if(fs_num==Fs1_Ring_En)
            Crunch_On();
        if(fs_num==Fs2_Tip_En)
            Lead1_On();
        if(fs_num==Fs2_Ring_En)
            Lead2_On();
    }
    DelaySwitch = StartChange;
}


void Clean_On()
{
	if(!U_PW0.pw0.Led_CLEAN)
		DelaySwitch = StartChange;
    U_PW0.pw0.Led_CLEAN = true;
    U_PW0.pw0.P4_CL_CR  = U_PW0.pw0.Tmp_CL_CR = U_PW0.pw0.P123_L1_L2 = U_PW0.pw0.P5_CC_LL = U_PW0.pw0.Led_CRUNCH = U_PW0.pw0.Led_LEAD1 = U_PW0.pw0.Led_LEAD2 = false;
}

void Crunch_On()
{
	if(!U_PW0.pw0.Led_CRUNCH)
		DelaySwitch = StartChange;
    U_PW0.pw0.Tmp_CL_CR = U_PW0.pw0.P4_CL_CR = U_PW0.pw0.Led_CRUNCH = true;
    U_PW0.pw0.P123_L1_L2 = U_PW0.pw0.P5_CC_LL = U_PW0.pw0.Led_CLEAN = U_PW0.pw0.Led_LEAD1 = U_PW0.pw0.Led_LEAD2 = false;
}

void Lead1_On()
{
	if(!U_PW0.pw0.Led_LEAD1)
		DelaySwitch = StartChange;
    U_PW0.pw0.Led_LEAD1 = U_PW0.pw0.P5_CC_LL = true;
    U_PW0.pw0.Tmp_L1_L2 = U_PW0.pw0.P123_L1_L2 = U_PW0.pw0.P4_CL_CR = U_PW0.pw0.Led_CRUNCH = U_PW0.pw0.Led_CLEAN = U_PW0.pw0.Led_LEAD2 = false;
}

void Lead2_On()
{
	if(!U_PW0.pw0.Led_LEAD2)
		DelaySwitch = StartChange;
    U_PW0.pw0.Tmp_L1_L2 = U_PW0.pw0.Led_LEAD2 = U_PW0.pw0.P123_L1_L2 = U_PW0.pw0.P5_CC_LL = true;
    U_PW0.pw0.P4_CL_CR = U_PW0.pw0.Led_CRUNCH = U_PW0.pw0.Led_CLEAN = U_PW0.pw0.Led_LEAD1 =false;
}

void Start_Delay(uint16_t Val, uint8_t Spi)
{                   
    uint8_t Del;
	if(Spi)
	    spi_transmit(Val);
    Del = 75;
    while(Del)
    {
        wdt_reset();
        if (Timer)
        {
            Timer = false;
            Del--;
        }
    }
}

void key_alarm()
{
    uint8_t DoAlarm;
	uint16_t LedAlarm;
    DoAlarm = false;
	LedAlarm = 0;
    Key_Flash++;
    if((Key_Flash&0b00111111)==0)
    {
        if(Key_Clean_Alarm)
        {
            DoAlarm = true;
			LedAlarm |= 0b0001000000000000;
//            U_PW0.pw0.Led_CLEAN ^= 1;
        }
        if(Key_Crunch_Alarm)
        {
            DoAlarm = true;
			LedAlarm |= 0b0000100000000000;
//            U_PW0.pw0.Led_CRUNCH ^= 1;
        }
        if(Key_Lead1_Alarm)
        {
            DoAlarm = true;
			LedAlarm |= 0b1000000000000000;
//            U_PW0.pw0.Led_LEAD1 ^= 1;
        }
        if(Key_Lead2_Alarm)
        {
            DoAlarm = true;
			LedAlarm |= 0b0010000000000000;
//            U_PW0.pw0.Led_LEAD2 ^= 1;
        }
        if(Key_Loop_Alarm)
        {
            DoAlarm = true;
			LedAlarm |= 0b0100000000000000;
//            U_PW0.pw0.Led_LOOP ^= 1;
        }
        if(Key_Master_Alarm)
        {
            DoAlarm = true;
			LedAlarm |= 0b0000011000000000;
//            U_PW0.pw0.Led_A = U_PW0.pw0.Led_B ^= 1;
        }
        if(DoAlarm)
			{
			if((Key_Flash&0b01000000))
	            spi_transmit(U_PW0.PW0|LedAlarm);
			else
	            spi_transmit(U_PW0.PW0&(0xffff-LedAlarm));				
			}
    }

    if((Key_Flash&0b00001111)==0)
    {
//        adc_data=ADCH;
//		if(adc_start)
//			{
//			adc_start--;
//			Power_Error = false;
//			}
//		else
//			{
//	        if((adc_data < 104) && (!Power_Error))
  // 	     		{
//            	Power_Error = true;
//            	DelaySwitch = StartChange;
//		    	MuteOn;
//        		}
//        	if ((adc_data > 107) && (Power_Error))
//        		{
//            	Power_Error = false;
//            	DelaySwitch = StartChange;
//        		}
//			}
//        ADCSRA |= 0b01000000;
	}
}


